package org.wesc.boot.secure.jwt;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.wesc.boot.dao.entity.User;
import org.wesc.boot.dao.redis.RedisConstants;
import org.wesc.boot.secure.properties.ShiroProperties;
import org.wesc.boot.secure.utils.EncryptUtil;
import org.wesc.boot.secure.utils.SpringContextUtil;

import java.util.Date;

/**
 * @author Wesley
 */
@Slf4j
public class JwtUtil {

    private static final long EXPIRE_TIME = SpringContextUtil.getBean(ShiroProperties.class).getJwtTimeOut() * 1000;

    /**
     * 校验token是否正确
     *
     * @param token  密钥
     * @param password 用户的密码
     * @return 是否正确
     */
    public static boolean verify(String token, String username, String password) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(password);
            JWTVerifier verifier = JWT.require(algorithm)
                    .withClaim(User.USER_NAME, username)
                    .build();
            verifier.verify(token);
            log.info("Token Verify Success");
            return true;
        } catch (Exception e) {
            log.error("Token Verify Failed: {}", e.getMessage());
            return false;
        }
    }

    /**
     * 从 token中获取用户名
     *
     * @return token中包含的用户名
     */
    public static String getUserName(String token) {
        if (null == token) {
            return null;
        }
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(User.USER_NAME).asString();
        } catch (JWTDecodeException e) {
            log.error("error：{}", e.getMessage());
            return null;
        }
    }

    /**
     * 生成 token
     *
     * @param username 用户名
     * @param password   用户的密码
     * @return token
     */
    public static String signature(String username, String password) {
        try {
            username = StringUtils.lowerCase(username);
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(password);
            return JWT.create()
                    .withClaim(User.USER_NAME, username)
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (Exception e) {
            log.error("error：{}", e.getMessage());
            return null;
        }
    }

    /**
     * token 加密
     *
     * @param token token
     * @return 加密后的 token
     */
    public static String encryptToken(String token) {
        try {
            EncryptUtil encryptUtil = new EncryptUtil(RedisConstants.TOKEN_CACHE_PREFIX);
            return encryptUtil.encrypt(token);
        } catch (Exception e) {
            log.error("token加密失败：" + e.getMessage());
            return null;
        }
    }

    /**
     * token 解密
     *
     * @param encryptToken 加密后的 token
     * @return 解密后的 token
     */
    public static String decryptToken(String encryptToken) {
        try {
            EncryptUtil encryptUtil = new EncryptUtil(RedisConstants.TOKEN_CACHE_PREFIX);
            return encryptUtil.decrypt(encryptToken);
        } catch (Exception e) {
            log.error("token解密失败：" + e.getMessage());
            return null;
        }
    }

    /**
     * 获取当前操作用户
     *
     * @return 用户信息
     */
    public static String getCurrentUserName() {
        String token = (String) SecurityUtils.getSubject().getPrincipal();
        return getUserName(token);
    }

}
